home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / edit / elv18src.zip / cmd1.c < prev    next >
C/C++ Source or Header  |  1994-01-10  |  39KB  |  1,976 lines

  1. /* cmd1.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains some of the EX commands - mostly ones that deal with
  12.  * files, options, etc. -- anything except text.
  13.  */
  14.  
  15. #include "config.h"
  16. #include "ctype.h"
  17. #include "vi.h"
  18. #include "regexp.h"
  19. #ifdef INTERNAL_TAGS
  20. # ifdef __STDC__
  21. #  include "string.h"
  22. # else
  23.    extern char *strrchr();
  24. # endif
  25. #endif
  26.  
  27. #ifndef NO_TAGSTACK
  28. /* These describe the current state of the tag related commands          */
  29. #define MAXTAGS    15
  30.  
  31. struct Tag_item {
  32.     MARK        tag_mark;
  33.     char        *tag_file;
  34. };
  35.  
  36. static struct Tag_item    tag_stack[MAXTAGS];
  37. static int        curr_tag = -1;
  38. #endif /* !NO_TAGSTACK */
  39.  
  40. #ifdef DEBUG
  41. /* print the selected lines with info on the blocks */
  42. /*ARGSUSED*/
  43. void cmd_debug(frommark, tomark, cmd, bang, extra)
  44.     MARK    frommark;
  45.     MARK    tomark;
  46.     CMD    cmd;
  47.     int    bang;
  48.     char    *extra;
  49. {
  50.     REG char    *scan;
  51.     REG long    l;
  52.     REG int        i;
  53.     int        len;
  54.  
  55.     /* scan lnum[] to determine which block its in */
  56.     l = markline(frommark);
  57.     for (i = 1; l > lnum[i]; i++)
  58.     {
  59.     }
  60.  
  61.     do
  62.     {
  63.         /* fetch text of the block containing that line */
  64.         scan = blkget(i)->c;
  65.  
  66.         /* calculate its length */
  67.         if (scan[BLKSIZE - 1])
  68.         {
  69.             len = BLKSIZE;
  70.         }
  71.         else
  72.         {
  73.             len = strlen(scan);
  74.         }
  75.  
  76.         /* print block stats */
  77.         msg("##### hdr[%d]=%d, lnum[%d-1]=%ld, lnum[%d]=%ld (%ld lines)",
  78.             i, hdr.n[i], i, lnum[i-1], i, lnum[i], lnum[i] - lnum[i - 1]);
  79.         msg("##### len=%d, buf=0x%lx, %sdirty",
  80.             len, scan, ((int *)scan)[MAXBLKS + 1] ? "" : "not ");
  81.         if (bang)
  82.         {
  83.             while (--len >= 0)
  84.             {
  85.                 addch(*scan);
  86.                 scan++;
  87.             }
  88.         }
  89.         exrefresh();
  90.  
  91.         /* next block */
  92.         i++;
  93.     } while (i < MAXBLKS && lnum[i] && lnum[i - 1] < markline(tomark));
  94. }
  95.  
  96.  
  97. /* This function checks a lot of conditions to make sure they aren't screwy */
  98. /*ARGSUSED*/
  99. void cmd_validate(frommark, tomark, cmd, bang, extra)
  100.     MARK    frommark;
  101.     MARK    tomark;
  102.     CMD    cmd;
  103.     int    bang;
  104.     char    *extra;
  105. {
  106.     char    *scan;
  107.     int    i;
  108.     int    nlcnt;    /* used to count newlines */
  109.     int    len;    /* counts non-NUL characters */
  110.  
  111.     /* check lnum[0] */
  112.     if (lnum[0] != 0L)
  113.     {
  114.         msg("lnum[0] = %ld", lnum[0]);
  115.     }
  116.  
  117.     /* check each block */
  118.     for (i = 1; lnum[i] <= nlines; i++)
  119.     {
  120.         scan = blkget(i)->c;
  121.         if (scan[BLKSIZE - 1])
  122.         {
  123.             msg("block %d has no NUL at the end", i);
  124.         }
  125.         else
  126.         {
  127.             for (nlcnt = len = 0; *scan; scan++, len++)
  128.             {
  129.                 if (*scan == '\n')
  130.                 {
  131.                     nlcnt++;
  132.                 }
  133.             }
  134.             if (scan[-1] != '\n')
  135.             {
  136.                 msg("block %d doesn't end with '\\n' (length %d)", i, len);
  137.             }
  138.             if (bang || nlcnt != lnum[i] - lnum[i - 1])
  139.             {
  140.                 msg("block %d (line %ld?) has %d lines, but should have %ld",
  141.                     i, lnum[i - 1] + 1L, nlcnt, lnum[i] - lnum[i - 1]);
  142.             }
  143.         }
  144.         exrefresh();
  145.     }
  146.  
  147.     /* check lnum again */
  148.     if (lnum[i] != INFINITY)
  149.     {
  150.         msg("hdr.n[%d] = %d, but lnum[%d] = %ld",
  151.             i, hdr.n[i], i, lnum[i]);
  152.     }
  153.  
  154.     msg("# = \"%s\", %% = \"%s\"", prevorig, origname);
  155.     msg("V_from=%ld.%d, cursor=%ld.%d", markline(V_from), markidx(V_from), markline(cursor), markidx(cursor));
  156. }
  157. #endif /* DEBUG */
  158.  
  159.  
  160. /*ARGSUSED*/
  161. void cmd_mark(frommark, tomark, cmd, bang, extra)
  162.     MARK    frommark;
  163.     MARK    tomark;
  164.     CMD    cmd;
  165.     int    bang;
  166.     char    *extra;
  167. {
  168.     /* validate the name of the mark */
  169.     if (*extra == '"')
  170.     {
  171.         extra++;
  172.     }
  173.     /* valid mark names are lowercase ascii characters */
  174.     if (!isascii(*extra) || !islower(*extra) || extra[1])
  175.     {
  176.         msg("Invalid mark name");
  177.         return;
  178.     }
  179.  
  180.     mark[*extra - 'a'] = tomark;
  181. }
  182.  
  183. /*ARGSUSED*/
  184. void cmd_write(frommark, tomark, cmd, bang, extra)
  185.     MARK    frommark;
  186.     MARK    tomark;
  187.     CMD    cmd;
  188.     int    bang;
  189.     char    *extra;
  190. {
  191.     int        fd;
  192.     int        append;    /* boolean: write in "append" mode? */
  193.     REG long    l;
  194.     REG char    *scan;
  195.     REG int        i;
  196.  
  197.     /* if writing to a filter, then let filter() handle it */
  198.     if (*extra == '!')
  199.     {
  200.         filter(frommark, tomark, extra + 1, FALSE);
  201.         return;
  202.     }
  203.  
  204.     /* if all lines are to be written, use tmpsave() */
  205.     if (frommark == MARK_FIRST && tomark == MARK_LAST && cmd == CMD_WRITE)
  206.     {
  207.         tmpsave(extra, bang);
  208.         return;
  209.     }
  210.  
  211.     /* see if we're going to do this in append mode or not */
  212.     append = FALSE;
  213.     if (extra[0] == '>' && extra[1] == '>')
  214.     {
  215.         extra += 2;
  216.         append = TRUE;
  217.     }
  218.  
  219.     /* either the file must not exist, or we must have a ! or be appending */
  220.     if (*extra && access(extra, 0) == 0 && !bang && !append)
  221.     {
  222.         msg("File already exists - Use :w! to overwrite");
  223.         return;
  224.     }
  225.  
  226.     /* else do it line-by-line, like cmd_print() */
  227.     if (append)
  228.     {
  229. #ifdef O_APPEND
  230.         fd = open(extra, O_WRONLY|O_APPEND);
  231. #else
  232.         fd = open(extra, O_WRONLY);
  233.         if (fd >= 0)
  234.         {
  235.             lseek(fd, 0L, 2);
  236.         }
  237. #endif
  238.     }
  239.     else
  240.     {
  241.         fd = -1; /* so we know the file isn't open yet */
  242.     }
  243.  
  244.     if (fd < 0)
  245.     {
  246.         fd = creat(extra, FILEPERMS);
  247.         if (fd < 0)
  248.         {
  249.             msg("Can't write to \"%s\"", extra);
  250.             return;
  251.         }
  252.     }
  253.     for (l = markline(frommark); l <= markline(tomark); l++)
  254.     {
  255.         /* get the next line */
  256.         scan = fetchline(l);
  257.         i = strlen(scan);
  258.         scan[i++] = '\n';
  259.  
  260.         /* print the line */
  261.         if (twrite(fd, scan, i) < i)
  262.         {
  263.             msg("Write failed");
  264.             break;
  265.         }
  266.     }
  267.     rptlines = markline(tomark) - markline(frommark) + 1;
  268.     rptlabel = "written";
  269. #if MSDOS
  270.     if (*o_controlz)
  271.     {
  272.         write(fd, "\032", 1);
  273.     }
  274. #endif
  275.     close(fd);
  276. }    
  277.  
  278.  
  279. /*ARGSUSED*/
  280. void cmd_shell(frommark, tomark, cmd, bang, extra)
  281.     MARK    frommark, tomark;
  282.     CMD    cmd;
  283.     int    bang;
  284.     char    *extra;
  285. {
  286.     static char    prevextra[132];
  287.  
  288.     /* special case: ":sh" means ":!sh" */
  289.     if (cmd == CMD_SHELL)
  290.     {
  291.         extra = o_shell;
  292.         frommark = tomark = 0L;
  293.     }
  294.  
  295.     /* if already did one or more shell commands, need extra newline to
  296.      * avoid overwriting user's command string */
  297.     if (mode == MODE_COLON)
  298.     {
  299.         addch('\n');
  300.     }
  301.  
  302.     /* if extra is "!", substitute previous command */
  303.     if (*extra == '!')
  304.     {
  305.         if (!*prevextra)
  306.         {
  307.             msg("No previous shell command to substitute for '!'");
  308.             return;
  309.         }
  310.         strcat(prevextra, extra + 1);
  311.         extra = prevextra;
  312.     }
  313.     else if (cmd == CMD_BANG && (unsigned)strlen(extra) < sizeof(prevextra) - 1)
  314.     {
  315.         strcpy(prevextra, extra);
  316.     }
  317.  
  318.     /* warn the user if the file hasn't been saved yet */
  319.     if (*o_warn && tstflag(file, MODIFIED))
  320.     {
  321.         if (mode == MODE_VI)
  322.         {
  323.             mode = MODE_COLON;
  324.         }
  325.         msg("Warning: \"%s\" has been modified but not yet saved", origname);
  326.     }
  327.  
  328.     /* if no lines were specified, just run the command */
  329.     suspend_curses();
  330.     if (frommark == 0L)
  331.     {
  332.         system(extra);
  333.     }
  334.     else /* pipe lines from the file through the command */
  335.     {
  336.         filter(frommark, tomark, extra, TRUE);
  337.     }
  338.  
  339.     /* resume curses quietly for MODE_EX, but noisily otherwise */
  340.     resume_curses(mode == MODE_EX);
  341. }
  342.  
  343.  
  344. /*ARGSUSED*/
  345. void cmd_global(frommark, tomark, cmd, bang, extra)
  346.     MARK    frommark, tomark;
  347.     CMD    cmd;
  348.     int    bang;
  349.     char    *extra;    /* rest of the command line */
  350. {
  351.     char    *cmdptr;    /* the command from the command line */
  352.     char    cmdln[100];    /* copy of the command from the command line */
  353.     char    *line;        /* a line from the file */
  354.     long    l;        /* used as a counter to move through lines */
  355.     long    lqty;        /* quantity of lines to be scanned */
  356.     long    nchanged;    /* number of lines changed */
  357.     regexp    *re;        /* the compiled search expression */
  358.  
  359.     /* can't nest global commands */
  360.     if (doingglobal)
  361.     {
  362.         msg("Can't nest global commands.");
  363.         rptlines = -1L;
  364.         return;
  365.     }
  366.  
  367.     /* ":g! ..." is the same as ":v ..." */
  368.     if (bang)
  369.     {
  370.         cmd = CMD_VGLOBAL;
  371.     }
  372.  
  373.     /* make sure we got a search pattern */
  374.     if (!*extra)
  375.     {
  376.         msg("Usage: %c /regular expression/ command", cmd == CMD_GLOBAL ? 'g' : 'v');
  377.         return;
  378.     }
  379.  
  380.     /* parse & compile the search pattern */
  381.     cmdptr = parseptrn(extra);
  382. #if 0
  383.     if (!extra[1])
  384.     {
  385.         msg("Can't use empty regular expression with '%c' command", cmd == CMD_GLOBAL ? 'g' : 'v');
  386.         return;
  387.     }
  388. #endif
  389.     re = regcomp(extra + 1);
  390.     if (!re)
  391.     {
  392.         /* regcomp found & described an error */
  393.         return;
  394.     }
  395.  
  396.     /* for each line in the range */
  397.     doingglobal = TRUE;
  398.     ChangeText
  399.     {
  400.         /* NOTE: we have to go through the lines in a forward order,
  401.          * otherwise "g/re/p" would look funny.  *BUT* for "g/re/d"
  402.          * to work, simply adding 1 to the line# on each loop won't
  403.          * work.  The solution: count lines relative to the end of
  404.          * the file.  Think about it.
  405.          */
  406.         for (l = nlines - markline(frommark),
  407.             lqty = markline(tomark) - markline(frommark) + 1L,
  408.             nchanged = 0L;
  409.              lqty > 0 && nlines - l >= 0 && nchanged >= 0L;
  410.              l--, lqty--)
  411.